package com.libra.assemble.service.authority;

import com.libra.assemble.entity.authority.User;
import com.libra.assemble.repository.authority.UserDao;
import com.libra.assemble.web.shiro.ShiroUser;
import com.libra.assemble.xutil.Constants;
import com.libra.assemble.xutil.Encodes;
import com.libra.assemble.xutil.enums.Status;
import com.libra.assemble.xutil.persistence.DynamicSpecifications;
import com.libra.assemble.xutil.persistence.SearchFilter;
import com.libra.assemble.xutil.security.Digests;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.Map;

/**
 * 用户管理的业务逻辑.
 *
 * @author Libra
 */
@Component
@Transactional
public class UserService {
    /**
     * 日志
     */
    private static Logger logger = LoggerFactory.getLogger(UserService.class);

    /**
     * 用户信息的数据访问接口
     */
    private UserDao userDao;

    @Autowired
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    /**
     * 通过ID取得用户信息.
     *
     * @param id
     * @return
     */
    public User getUser(Long id) {
        return userDao.findOne(id);
    }

    /**
     * 登录,通过用户名取得用户信息.
     *
     * @param loginName
     * @return
     */
    public User findUserByLoginName(String loginName) {
        return userDao.findByLoginNameAndStatus(loginName, Status.NORMAL);
    }

    /**
     * 用户注册.
     *
     * @param user
     */
    public void registerUser(User user) {
        entryptPassword(user);
        Date now = new Date();
        user.setCreateTime(now);
        user.setUpdateTime(now);
        user.setRegisterDate(now);
        userDao.save(user);
    }

    /**
     * 更新用户信息.
     *
     * @param user
     */
    public void updateUser(User user) {
        if (StringUtils.isNotBlank(user.getPlainPassword())) {
            entryptPassword(user);
        }
        user.setUpdateTime(new Date());
        userDao.save(user);
    }

    /**
     * 删除用户信息.
     *
     * @param id
     */
    public void deleteUser(Long id) {
        if (isSupervisor(id)) {
            logger.warn("操作员{}尝试删除超级管理员用户", getCurrentUserName());
        } else {
            User user = getUser(id);
            user.setStatus(Status.DELETE);
            updateUser(user);
        }
    }

    /**
     * 判断是否超级管理员.
     *
     * @param id
     * @return
     */
    private boolean isSupervisor(Long id) {
        return id == 1;
    }

    /**
     * 取出Shiro中的当前用户LoginName.
     *
     * @return
     */
    private String getCurrentUserName() {
        ShiroUser user = (ShiroUser) SecurityUtils.getSubject().getPrincipal();
        return user.loginName;
    }

    /**
     * 设定安全的密码，生成随机的salt并经过1024次 sha-1 hash.
     *
     * @param user
     */
    private void entryptPassword(User user) {
        byte[] salt = Digests.generateSalt(Constants.SALT_SIZE);
        user.setSalt(Encodes.encodeHex(salt));

        byte[] hashPassword = Digests.sha1(user.getPlainPassword().getBytes(), salt, Constants.HASH_INTERATIONS);
        user.setPassword(Encodes.encodeHex(hashPassword));
    }

    /**
     * 将传入的密码进行指定的盐值加密，返回加密后的字符串，主要用于判断两个密码是否相同.
     *
     * @param salt
     * @param password
     * @return
     */
    public String entryptPassword(String salt, String password) {
        byte[] hashPassword = Digests.sha1(password.getBytes(), Encodes.decodeHex(salt), Constants.HASH_INTERATIONS);
        return Encodes.encodeHex(hashPassword);
    }

    /**
     * 获取用户信息[查询、分页、排序].
     *
     * @param searchParams
     * @param pageNumber
     * @param pageSize
     * @return
     */
    public Page<User> getUser(Map<String, Object> searchParams, int pageNumber, int pageSize) {
        PageRequest pageRequest = new PageRequest(pageNumber - 1, pageSize, new Sort(Direction.DESC, "id"));
        Specification<User> spec = buildSpecification(searchParams);
        return userDao.findAll(spec, pageRequest);
    }

    /**
     * 创建动态查询条件组合.
     *
     * @param searchParams
     * @return
     */
    private Specification<User> buildSpecification(Map<String, Object> searchParams) {
        Map<String, SearchFilter> filters = SearchFilter.parse(searchParams);
        Specification<User> spec = DynamicSpecifications.bySearchFilter(filters.values(), User.class);
        return spec;
    }

}
